package agh.gs.semdrools;

import java.rmi.server.UnicastRemoteObject;
import java.util.Arrays;
import java.util.Map;
import java.util.List;

import org.drools.KnowledgeBase;
import org.drools.KnowledgeBaseFactory;
import org.drools.agent.KnowledgeAgent;
import org.drools.agent.KnowledgeAgentFactory;
import org.drools.builder.KnowledgeBuilder;
import org.drools.builder.KnowledgeBuilderError;
import org.drools.builder.KnowledgeBuilderErrors;
import org.drools.builder.KnowledgeBuilderFactory;
import org.drools.builder.ResourceType;
import org.drools.io.Resource;
import org.drools.io.ResourceChangeScannerConfiguration;
import org.drools.io.ResourceFactory;
import org.drools.runtime.StatefulKnowledgeSession;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import agh.gs.semdrools.alarm.AlarmListener;

import pl.edu.agh.msc.monitoring.metric.IAlarmSubscriber;
import pl.edu.agh.msc.monitoring.metric.IRunningMetricsManager;


public class SemDrools extends Thread {

	private static KnowledgeBase readKnowledgeBase( List< String > resources ) throws Exception {
				
		KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
		
		for ( String resource : resources ) {
			
			kbuilder.add( ResourceFactory.newClassPathResource( resource ), ResourceType.DRL );
			
		}
				
		KnowledgeBuilderErrors errors = kbuilder.getErrors();
		if ( errors.size() > 0 ) {
			
			for ( KnowledgeBuilderError error : errors ) {
				System.err.println( error );
			}
			
			throw new IllegalArgumentException( "Could not parse knowledge." );
			
		}
				
		KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
		kbase.addKnowledgePackages( kbuilder.getKnowledgePackages() );
		
		return kbase;
	}
	
	
	@SuppressWarnings( "unchecked" )
	private void init( String args[] ) throws Exception {
		
		SessionProvider sessionProvider = null;
		
		ApplicationContext ctx = new ClassPathXmlApplicationContext( "spring/context.xml" );
		
		if ( ( args.length > 0 ) && ( args[ 0 ].compareTo( "local" ) == 0 ) ) {
			
	    	KnowledgeBase kbase = readKnowledgeBase( Arrays.asList(
	    		"rules/Alarms.drl",
	    		"rules/Logger.drl"
			) );
	    	
	    	StatefulKnowledgeSession session = kbase.newStatefulKnowledgeSession();
	    	session.fireAllRules();
	    	
	    	sessionProvider = new LocalSessionProvider( session );
			
		} else {
		
			Map< String, String > config = ( Map< String, String > ) ctx.getBean( "config" );
			
			ResourceChangeScannerConfiguration conf = ResourceFactory
			                                          	.getResourceChangeScannerService()
			                                          	.newResourceChangeScannerConfiguration();
			conf.setProperty( "drools.resource.scanner.interval",
			                  config.get( "scan.interval" ) );
			
			ResourceFactory.getResourceChangeScannerService().configure( conf );
			
			ResourceFactory.getResourceChangeNotifierService().start();
			ResourceFactory.getResourceChangeScannerService().start();
			
			Resource resource = ResourceFactory.newClassPathResource(
				"rules/change-set.xml"
			);
			
			KnowledgeAgent kagent = KnowledgeAgentFactory.newKnowledgeAgent( "SemDrools" );
			kagent.applyChangeSet( resource );
			
			sessionProvider = new AgentSessionProvider( kagent );
		
		}
		
		IRunningMetricsManager runningMetricsManager = ( IRunningMetricsManager ) ctx.getBean( "runningMetricsManager" );
		
		sessionProvider.provide().insert( runningMetricsManager );
		
		IAlarmSubscriber listener = ( IAlarmSubscriber ) UnicastRemoteObject.exportObject(
			new AlarmListener( sessionProvider ), 0
		);
		
		if ( ! runningMetricsManager.subscribeToAlarms( listener ) ) {
			
			throw new Exception( "Error while subscribing to alarms" );
			
		}
		
	}
	
	
	/**
	 * @param args
	 */
	public static void main( String args[] ) throws Exception {
		
		( new SemDrools() ).init( args );
		System.in.read();
		
	}
	
}
